#include <vtkForceDirectedLayoutStrategy.h>
#include <vtkGraphLayoutView.h>
#include <vtkMutableUndirectedGraph.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>

#include <vtkArcSource.h>
#include <vtkPolyDataMapper.h>
#include "vtkPolygon.h"
#include "vtkProperty.h"

#include "vtkLookupTable.h"
#include "vtkMinimalStandardRandomSequence.h"
#include "vtkCellData.h"

#include "vtkInteractorStyleTrackballCamera.h"

void RandomColors(vtkLookupTable* lut, int numberOfColors)
{
    // Fill in a few known colors, the rest will be generated if needed
    vtkNew<vtkNamedColors> colors;
    lut->SetTableValue(0, colors->GetColor4d("Black").GetData());
    lut->SetTableValue(1, colors->GetColor4d("Banana").GetData());
    lut->SetTableValue(2, colors->GetColor4d("Tomato").GetData());
    lut->SetTableValue(3, colors->GetColor4d("Wheat").GetData());
    lut->SetTableValue(4, colors->GetColor4d("Lavender").GetData());
    lut->SetTableValue(5, colors->GetColor4d("Flesh").GetData());
    lut->SetTableValue(6, colors->GetColor4d("Raspberry").GetData());
    lut->SetTableValue(7, colors->GetColor4d("Salmon").GetData());
    lut->SetTableValue(8, colors->GetColor4d("Mint").GetData());
    lut->SetTableValue(9, colors->GetColor4d("Peacock").GetData());

    // If the number of colors is larger than the number of specified colors,
    // generate some random colors.
    vtkNew<vtkMinimalStandardRandomSequence> randomSequence;
    randomSequence->SetSeed(4355412);
    if (numberOfColors > 9)
    {
        for (auto i = 10; i < numberOfColors; ++i)
        {
            double r, g, b;
            r = randomSequence->GetRangeValue(0.6, 1.0);
            randomSequence->Next();
            g = randomSequence->GetRangeValue(0.6, 1.0);
            randomSequence->Next();
            b = randomSequence->GetRangeValue(0.6, 1.0);
            randomSequence->Next();
            lut->SetTableValue(i, r, g, b, 1.0);
        }
    }
}

int main(int, char*[]) {
    vtkNew<vtkRenderer> renderer;
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->SetWindowName("RegularPolygonSource");
    renderWindow->AddRenderer(renderer);
    vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
//    renderWindowInteractor->SetInteractorStyle(vtkNew<vtkInteractorStyleTrackballCamera>)
    renderWindowInteractor->SetRenderWindow(renderWindow);


    vtkNew<vtkNamedColors> colors;


    const int RowCount = 36;
    const int ColCount = 40;
    const double RowDegree = vtkMath::Pi() * 2 / RowCount;
    const double Radius = 500;
    const int AreaAvgRadius = Radius / ColCount;
    const int ArcSegmentCount = 1;
    double ArcSegmentDegree = RowDegree / ArcSegmentCount;
    double fyjDegree = 10.0;

    double colZList[ColCount];
    colZList[0] = 0;
    for (int j = 0; j < ColCount; ++j) {
        double radius1 = (j + 1) * AreaAvgRadius;
        double z = sin(vtkMath::RadiansFromDegrees(10.0)) * radius1;
        colZList[j + 1] = z;
    }

    vtkNew<vtkCellArray> allPolygons;
    vtkNew<vtkPoints> allPoints;
    vtkNew<vtkPolyData> polygonPolyData;

    for (int i = 0; i < RowCount; ++i) {

        double degree = RowDegree * i;

        for (int j = 0; j < ColCount; ++j) {

            vtkNew<vtkPolygon> polygon;
            polygon->GetPointIds()->SetNumberOfIds((ArcSegmentCount + 1) * 2);
            vtkIdType numberOfPoints = allPoints->GetNumberOfPoints();

            double radius0 = j * AreaAvgRadius;
            double radius1 = (j + 1) * AreaAvgRadius;

            double z0 = colZList[j];
            double z1 = colZList[j + 1];

            for (int k = 0; k < ArcSegmentCount + 1; ++k) {
                double d0 = degree + (ArcSegmentDegree) * k;
                double x0 = cos(d0) * radius0;
                double y0 = sin(d0) * radius0;
                allPoints->InsertNextPoint(x0, y0, z0);

                double d1 = degree + (ArcSegmentDegree) * k;
                double x1 = cos(d1) * radius1;
                double y1 = sin(d1) * radius1;
                allPoints->InsertNextPoint(x1, y1, z1);

                polygon->GetPointIds()->SetId(k, numberOfPoints + (ArcSegmentCount - k));
                polygon->GetPointIds()->SetId(k + ArcSegmentCount + 1, numberOfPoints + ArcSegmentCount + 1 + k);
            }

            allPolygons->InsertNextCell(polygon);
        }
    }

    polygonPolyData->SetPoints(allPoints);
    polygonPolyData->SetPolys(allPolygons);

    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputData(polygonPolyData);


    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    actor->GetProperty()->EdgeVisibilityOn();
    renderer->AddActor(actor);


    renderWindow->Render();
    renderWindowInteractor->Initialize();
    renderWindowInteractor->Start();


    vtkNew<vtkUnsignedCharArray> cellData;
    cellData->SetNumberOfComponents(3);
    cellData->SetNumberOfTuples(polygonPolyData->GetNumberOfCells());

    vtkNew<vtkMinimalStandardRandomSequence> randomSequence;
    randomSequence->SetSeed(8775070);
    auto min_r = 64.0;
    auto max_r = 255.0;
    for (int i = 0; i < polygonPolyData->GetNumberOfCells(); i++)
    {
        double rgb[3];
        for (auto j = 0; j < 3; ++j)
        {
            rgb[j] = randomSequence->GetRangeValue(min_r, max_r);
            randomSequence->Next();
        }
        cellData->InsertTuple(i, rgb);
    }

    polygonPolyData->GetCellData()->SetScalars(cellData);
    actor->Modified();
    renderWindow->Render();
    renderWindowInteractor->Render();



    return EXIT_SUCCESS;
}